home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / zhm / zhm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-21  |  14.3 KB  |  557 lines

  1. /* This file is part of the Project Athena Zephyr Notification System.
  2.  * It contains the hostmanager client program.
  3.  *
  4.  *      Created by:     David C. Jedlinsky
  5.  *
  6.  *      $Source: /usr/sww/share/src/Zephyr/src/zhm/RCS/zhm.c,v $
  7.  *      $Author: smoot $
  8.  *
  9.  *      Copyright (c) 1987,1991 by the Massachusetts Institute of Technology.
  10.  *      For copying and distribution information, see the file
  11.  *      "mit-copyright.h". 
  12.  */
  13.  
  14. #include "zhm.h"
  15.  
  16. static char rcsid_hm_c[] = "$Id: zhm.c,v 1.49.1.6 1992/09/21 23:33:06 smoot Exp $";
  17.  
  18. #include <ctype.h>
  19. #include <signal.h>
  20. #include <sys/ioctl.h>
  21. #include <sys/file.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. /* 
  25.  * warning: sys/param.h may include sys/types.h which may not be protected from
  26.  * multiple inclusions on your system
  27.  */
  28. #include <sys/param.h>
  29.  
  30. #ifdef Z_HaveHesiod
  31. #include <hesiod.h>
  32. #endif
  33.  
  34. #ifdef macII
  35. #define srandom srand48
  36. #endif
  37.  
  38. int hmdebug, rebootflag, errflg, dieflag, inetd, oldpid;
  39. int no_server = 1, nservchang, nserv, nclt;
  40. int booting = 1, timeout_type, deactivated = 1;
  41. long starttime;
  42. u_short cli_port;
  43. struct sockaddr_in cli_sin, serv_sin, from;
  44. char **serv_list, **cur_serv_list;
  45. char prim_serv[MAXHOSTNAMELEN], cur_serv[MAXHOSTNAMELEN];
  46. char *zcluster;
  47. int sig_type;
  48. struct hostent *hp;
  49. char **clust_info;
  50. char hostname[MAXHOSTNAMELEN], loopback[4];
  51. char PidFile[MAXPATHLEN];
  52.  
  53. extern char *index(), *sbrk();
  54.  
  55. void init_hm(), detach(), handle_timeout(), resend_notices(), die_gracefully();
  56.  
  57. #if defined(ultrix) || defined(_POSIX_SOURCE)
  58. void
  59. #endif
  60.   set_sig_type(sig)
  61.      int sig;
  62. {
  63.      sig_type = sig;
  64. }
  65.  
  66. char *strsave();
  67.  
  68. main(argc, argv)
  69. char *argv[];
  70. {
  71.      ZNotice_t notice;
  72.      ZPacket_t packet;
  73.      Code_t ret;
  74.      int opt, pak_len;
  75.      extern int optind;
  76.      register int i, j = 0;
  77.  
  78.      if (gethostname(hostname, MAXHOSTNAMELEN) < 0) {
  79.       printf("Can't find my hostname?!\n");
  80.       exit(-1);
  81.      }
  82.      prim_serv[0] = '\0';
  83.      while ((opt = getopt(argc, argv, "drhi")) != EOF)
  84.       switch(opt) {
  85.       case 'd':
  86.            hmdebug++;
  87.            break;
  88.       case 'h':
  89.            /* Die on SIGHUP */
  90.            dieflag++;
  91.            break;
  92.       case 'r':
  93.            /* Reboot host -- send boot notice -- and exit */
  94.            rebootflag++;
  95.            break;
  96.       case 'i':
  97.            /* inetd operation: don't do bind ourselves, fd 0 is
  98.           already connected to a socket. Implies -h */
  99.            inetd++;
  100.            dieflag++;
  101.            break;
  102.       case '?':
  103.       default:
  104.            errflg++;
  105.            break;
  106.       }
  107.      if (errflg) {
  108.       fprintf(stderr, "Usage: %s [-d] [-h] [-r] [server]\n", argv[0]);
  109.       exit(2);
  110.      }
  111.  
  112.      /* Override server argument? */
  113.      if (optind < argc) {
  114.      if ((hp = gethostbyname(argv[optind++])) == NULL) {
  115.          printf("Unknown server name: %s\n", argv[optind-1]);
  116.      } else
  117.          (void) strcpy(prim_serv, hp->h_name);
  118.      /* argc-optind is the # of other servers on the command line */
  119.      serv_list = (char **)malloc((argc-optind + 2) * sizeof(char *));
  120.      serv_list[0] = prim_serv;
  121.      for (i = 1; optind < argc; optind++) {
  122.          if ((hp = gethostbyname(argv[optind])) == NULL) {
  123.          printf("Unknown server name '%s', ignoring\n", argv[optind]);
  124.          continue;
  125.          }
  126.          serv_list[i] = strsave(hp->h_name);
  127.          i++;
  128.      }
  129.      serv_list[i] = NULL;
  130.      }
  131. #ifdef Z_HaveHesiod
  132.      else {
  133.  
  134.      if ((clust_info = hes_resolve(hostname, "CLUSTER")) == NULL) {
  135.          zcluster = NULL;
  136.      } else
  137.          for ( ; *clust_info; clust_info++) {
  138.          /* Remove the following check once we have changed over to
  139.           * new Hesiod format (i.e. ZCLUSTER.sloc lookup, no primary
  140.           * server
  141.           */
  142.          if (!strncasecmp("ZEPHYR", *clust_info, 6)) {
  143.              register char *c;
  144.     
  145.              if ((c = index(*clust_info, ' ')) == 0) {
  146.              printf("Hesiod error getting primary server info.\n");
  147.              } else
  148.              (void)strcpy(prim_serv, c+1);
  149.              break;
  150.          }
  151.          if (!strncasecmp("ZCLUSTER", *clust_info, 9)) {
  152.              register char *c;
  153.  
  154.              if ((c = index(*clust_info, ' ')) == 0) {
  155.              printf("Hesiod error getting zcluster info.\n");
  156.              } else {
  157.              if ((zcluster = malloc((unsigned)(strlen(c+1)+1)))
  158.                  != NULL) {
  159.                  (void)strcpy(zcluster, c+1);
  160.              } else {
  161.                  printf("Out of memory.\n");
  162.                  exit(-5);
  163.              }
  164.              }
  165.              break;
  166.          }
  167.          }
  168.       
  169.      if (zcluster == NULL) {
  170.          if ((zcluster = malloc((unsigned)(strlen("zephyr")+1))) != NULL)
  171.          (void)strcpy(zcluster, "zephyr");
  172.      }
  173.      while ((serv_list = hes_resolve(zcluster, "sloc")) == (char **)NULL) {
  174.          syslog(LOG_ERR, "No servers or no hesiod");
  175.          /* wait a bit, and try again */
  176.          sleep(30);
  177.      }
  178.      clust_info = (char **)malloc(2*sizeof(char *));
  179.      if (prim_serv[0]) {
  180.          clust_info[0] = prim_serv;
  181.          j = 1;
  182.      } else
  183.          j = 0;
  184.      for (i = 0; serv_list[i]; i++)
  185.          /* copy in non-duplicates */
  186.          /* assume the names returned in the sloc are full domain names */
  187.          if (!prim_serv[0] || strcasecmp(prim_serv, serv_list[i])) {
  188.          clust_info = (char **) realloc(clust_info,
  189.                         (j+2) * sizeof(char *));
  190.          clust_info[j++] = strsave(serv_list[i]);
  191.          }
  192.      clust_info[j] = NULL;
  193.      serv_list = clust_info;
  194.      }
  195.      if (!prim_serv[0] && j) {
  196.      srandom(time((long *) 0));
  197.      (void) strcpy(prim_serv, serv_list[random() % j]);
  198.      }
  199. #endif
  200.      if (*prim_serv == '\0') {
  201.        /* nothing found so far; try to use "zephyr-server" as a hostname */
  202.        if (hp = gethostbyname("zephyr-server.cs.berkeley.edu")) {
  203.      (void) strcpy(prim_serv, hp->h_name);
  204.      /* argc-optind is the # of other servers on the command line */
  205.      serv_list = (char **)malloc(2 * sizeof(*serv_list));
  206.      serv_list[0] = prim_serv;
  207.      serv_list[1] = 0;
  208.        } else {
  209.      printf("No valid primary server found, exiting.\n");
  210.      exit(ZERR_SERVNAK);
  211.        }
  212.      }
  213.      init_hm();
  214.  
  215.      DPR2 ("zephyr server port: %u\n", ntohs(serv_sin.sin_port));
  216.      DPR2 ("zephyr client port: %u\n", ntohs(cli_port));
  217.   
  218.      /* Main loop */
  219.      for ever {
  220.       DPR ("Waiting for a packet...");
  221.       switch(sig_type) {
  222.       case 0:
  223.            break;
  224.       case SIGHUP:    /* A SIGHUP means we are deactivating the ws. */
  225.            sig_type = 0;
  226.            if (dieflag) {
  227.             die_gracefully();
  228.            } else {
  229.             send_flush_notice(HM_FLUSH);
  230.             deactivated = 1;
  231.            }
  232.            break;
  233.       case SIGTERM:
  234.            sig_type = 0;
  235.            die_gracefully();
  236.            break;
  237.       case SIGALRM:
  238.            sig_type = 0;
  239.            handle_timeout();
  240.            break;
  241.       default:
  242.            sig_type = 0;
  243.            syslog (LOG_WARNING, "Unknown system interrupt.");
  244.            break;
  245.       }
  246.       ret = ZReceivePacket(packet, &pak_len, &from);
  247.       if ((ret != ZERR_NONE) && (ret != EINTR)){
  248.            Zperr(ret);
  249.            com_err("hm", ret, "receiving notice");
  250.       } else if (ret != EINTR) {
  251.            /* Where did it come from? */
  252.            if ((ret = ZParseNotice(packet, pak_len, ¬ice))
  253.            != ZERR_NONE) {
  254.            Zperr(ret);
  255.            com_err("hm", ret, "parsing notice");
  256.           } else {
  257.            DPR ("Got a packet.\n");
  258.            DPR ("notice:\n");
  259.            DPR2("\tz_kind: %d\n", notice.z_kind);
  260.            DPR2("\tz_port: %u\n", ntohs(notice.z_port));
  261.            DPR2("\tz_class: %s\n", notice.z_class);
  262.            DPR2("\tz_class_inst: %s\n", notice.z_class_inst);
  263.            DPR2("\tz_opcode: %s\n", notice.z_opcode);
  264.            DPR2("\tz_sender: %s\n", notice.z_sender);
  265.            DPR2("\tz_recip: %s\n", notice.z_recipient);
  266.            DPR2("\tz_def_format: %s\n", notice.z_default_format);
  267.            DPR2("\tz_message: %s\n", notice.z_message);
  268.            if ((bcmp(loopback, (char *)&from.sin_addr, 4) != 0) &&
  269.                ((notice.z_kind == SERVACK) ||
  270.             (notice.z_kind == SERVNAK) ||
  271.             (notice.z_kind == HMCTL))) {
  272.                server_manager(¬ice);
  273.           } else {
  274.                if ((bcmp(loopback, (char *)&from.sin_addr, 4) == 0) &&
  275.                ((notice.z_kind == UNSAFE) ||
  276.                 (notice.z_kind == UNACKED) ||
  277.                 (notice.z_kind == ACKED) ||
  278.                 (notice.z_kind == HMCTL))) {
  279.                /* Client program... */
  280.                if (deactivated) {
  281.                 send_boot_notice(HM_BOOT);
  282.                 deactivated = 0;
  283.                }
  284.                transmission_tower(¬ice, packet, pak_len);
  285.                DPR2 ("Pending = %d\n", ZPending());
  286.               } else {
  287.                if (notice.z_kind == STAT) {
  288.                 send_stats(¬ice, &from);
  289.                } else {
  290.                 syslog(LOG_INFO,
  291.                        "Unknown notice type: %d",
  292.                        notice.z_kind);
  293.                }
  294.               }
  295.           }
  296.           }
  297.       }
  298.      }
  299. }
  300.  
  301. void init_hm()
  302. {
  303.      struct servent *sp;
  304.      Code_t ret;
  305.      FILE *fp;
  306.  
  307.      starttime = time((time_t *)0);
  308.      OPENLOG("hm", LOG_PID, LOG_DAEMON);
  309.   
  310.      if ((ret = ZInitialize()) != ZERR_NONE) {
  311.       Zperr(ret);
  312.       com_err("hm", ret, "initializing");
  313.       closelog();
  314.       exit(-1);
  315.      }
  316.      (void)ZSetServerState(1);    /* Aargh!!! */
  317.      init_queue();
  318.  
  319.      cur_serv_list = serv_list;
  320.      if (*prim_serv == '\0')
  321.       (void)strcpy(prim_serv, *cur_serv_list);
  322.   
  323. #ifdef sprite
  324.      {
  325.          struct hostent *hentry;
  326.  
  327.          if ((hentry=gethostbyname(hostname)) == NULL) {
  328.              herror("init_hm");
  329.              exit(-1);
  330.          }
  331.          bcopy(hentry->h_addr, loopback, 4);
  332.      }
  333.  
  334.      /* kill old hm if it exists */
  335.      strcpy(PidFile, "/hosts/");
  336.      strcat(PidFile, hostname);
  337.      strcat(PidFile, "/");
  338.      strcat(PidFile, PIDFILE);
  339. #else
  340.      loopback[0] = 127;
  341.      loopback[1] = 0;
  342.      loopback[2] = 0;
  343.      loopback[3] = 1;
  344.  
  345.      /* kill old hm if it exists */
  346.      strcpy(PidFile, PIDFILE);
  347. #endif
  348.      
  349.      fp = fopen(PidFile, "r");
  350.      if (fp != NULL) {
  351.       (void)fscanf(fp, "%d\n", &oldpid);
  352.       while (!kill(oldpid, SIGTERM))
  353.            sleep(1);
  354.       syslog(LOG_INFO, "Killed old image.");
  355.       (void) fclose(fp);
  356.      }
  357.  
  358.      if (inetd) {
  359.          (void) ZSetFD(0);        /* fd 0 is on the socket,
  360.                        thanks to inetd */
  361.      } else {
  362.          /* Open client socket, for receiving client and server notices */
  363.          if ((sp = getservbyname(HM_SVCNAME, "udp")) == NULL) {
  364.            fprintf(stderr,"Warning: service '%s' not in /etc/services or equivalent;\n\tassuming port 2104\n", HM_SVCNAME);
  365.              cli_port = htons(2104);
  366.          } else
  367.          cli_port = sp->s_port;
  368.       
  369.          if ((ret = ZOpenPort(&cli_port)) != ZERR_NONE) {
  370.              Zperr(ret);
  371.              com_err("hm", ret, "opening port");
  372.              exit(ret);
  373.          }
  374.      }
  375.      cli_sin = ZGetDestAddr();
  376.   
  377.      /* Open the server socket */
  378.  
  379.      bzero((char *)&serv_sin, sizeof(struct sockaddr_in));
  380.      if ((sp = getservbyname(SERVER_SVCNAME, "udp")) == NULL) {
  381.            fprintf(stderr,"Warning: service '%s' not in /etc/services or equivalent;\n\tassuming port 2103\n", SERVER_SVCNAME);
  382.            serv_sin.sin_port = htons(2103);
  383.      } else
  384.      serv_sin.sin_port = sp->s_port;
  385.   
  386. #ifndef DEBUG
  387.      if (!inetd)
  388.          detach();
  389.   
  390.      /* Write pid to file */
  391.      fp = fopen(PidFile, "w");
  392.      if (fp != NULL) {
  393.          fprintf(fp, "%d\n", getpid());
  394.          (void) fclose(fp);
  395.      }
  396. #endif /* DEBUG */
  397.  
  398.      if (hmdebug) {
  399.       syslog(LOG_INFO, "Debugging on.");
  400.      }
  401.       
  402.      /* Set up communications with server */
  403.      /* target is SERVER_SVCNAME port on server machine */
  404.  
  405.      serv_sin.sin_family = AF_INET;
  406.   
  407.      /* who to talk to */
  408.      if ((hp = gethostbyname(prim_serv)) == NULL) {
  409.       DPR("gethostbyname failed\n");
  410.       find_next_server((char *)NULL);
  411.      } else {
  412.       DPR2 ("Server = %s\n", prim_serv);
  413.       (void)strcpy(cur_serv, prim_serv);
  414.       bcopy(hp->h_addr, (char *)&serv_sin.sin_addr, hp->h_length);
  415.      }
  416.  
  417.      send_boot_notice(HM_BOOT);
  418.      deactivated = 0;
  419.   
  420.      (void)signal (SIGHUP,  set_sig_type);
  421.      (void)signal (SIGALRM, set_sig_type);
  422.      (void)signal (SIGTERM, set_sig_type);
  423. }
  424.  
  425. void detach()
  426. {
  427.      /* detach from terminal and fork. */
  428.      register int i, x = ZGetFD(), size = getdtablesize();
  429.   
  430.      if (i = fork()) {
  431.       if (i < 0)
  432.            perror("fork");
  433.       exit(0);
  434.      }
  435.  
  436.      for (i = 0; i < size; i++)
  437.       if (i != x)
  438.            (void) close(i);
  439.   
  440.      if ((i = open("/dev/tty", O_RDWR, 666)) < 0)
  441.       ;        /* Can't open tty, but don't flame about it. */
  442.      else {
  443.       (void) ioctl(i, TIOCNOTTY, (caddr_t) 0);
  444.       (void) close(i);
  445.      }
  446. }
  447.  
  448. static char version[BUFSIZ];
  449.  
  450. send_stats(notice, sin)
  451.      ZNotice_t *notice;
  452.      struct sockaddr_in *sin;
  453. {
  454.      ZNotice_t newnotice;
  455.      Code_t ret;
  456.      char *bfr;
  457.      char *list[20];
  458.      int len, i, nitems = 10;
  459.      unsigned int size;
  460.  
  461.      newnotice = *notice;
  462.      
  463.      if ((ret = ZSetDestAddr(sin)) != ZERR_NONE) {
  464.       Zperr(ret);
  465.       com_err("hm", ret, "setting destination");
  466.      }
  467.      newnotice.z_kind = HMACK;
  468.  
  469.      list[0] = (char *)malloc(MAXHOSTNAMELEN);
  470.      (void)strcpy(list[0], cur_serv);
  471.      list[1] = (char *)malloc(64);
  472.      (void)sprintf(list[1], "%d", queue_len());
  473.      list[2] = (char *)malloc(64);
  474.      (void)sprintf(list[2], "%d", nclt);
  475.      list[3] = (char *)malloc(64);
  476.      (void)sprintf(list[3], "%d", nserv);
  477.      list[4] = (char *)malloc(64);
  478.      (void)sprintf(list[4], "%d", nservchang);
  479.      list[5] = (char *)malloc(64);
  480.      (void)strcpy(list[5], rcsid_hm_c);
  481.      list[6] = (char *)malloc(64);
  482.      if (no_server)
  483.       (void)sprintf(list[6], "yes");
  484.      else
  485.       (void)sprintf(list[6], "no");
  486.      list[7] = (char *)malloc(64);
  487.      (void)sprintf(list[7], "%ld", time((time_t *)0) - starttime);
  488. #ifdef adjust_size
  489.      size = (unsigned int)sbrk(0);
  490.      adjust_size (size);
  491. #else
  492.      size = -1;
  493. #endif
  494.      list[8] = (char *)malloc(64);
  495.      (void)sprintf(list[8], "%ld", size);
  496.      list[9] = (char *)malloc(32);
  497.      (void)strcpy(list[9], MACHINE);
  498.  
  499.      /* Since ZFormatRaw* won't change the version number on notices,
  500.     we need to set the version number explicitly.  This code is taken
  501.     from Zinternal.c, function Z_FormatHeader */
  502.      if (!*version)
  503.          (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR,
  504.                 ZVERSIONMINOR);
  505.      newnotice.z_version = version;
  506.  
  507.      if ((ret = ZFormatRawNoticeList(&newnotice, list, nitems, &bfr,
  508.                      &len)) != ZERR_NONE) {
  509.       syslog(LOG_INFO, "Couldn't format stats packet");
  510.      } else
  511.       if ((ret = ZSendPacket(bfr, len, 0)) != ZERR_NONE) {
  512.            Zperr(ret);
  513.            com_err("hm", ret, "sending stats");
  514.       }
  515.      free(bfr);
  516.      for(i=0;i<nitems;i++)
  517.       free(list[i]);
  518. }
  519.  
  520. void handle_timeout()
  521. {
  522.      switch(timeout_type) {
  523.      case BOOTING:
  524.       new_server((char *)NULL);
  525.       break;
  526.      case NOTICES:
  527.       DPR ("Notice timeout\n");
  528.       resend_notices(&serv_sin);
  529.       break;
  530.      default:
  531.       syslog (LOG_ERR, "Unknown timeout type: %d\n", timeout_type);
  532.       break;
  533.      }
  534. }
  535.  
  536. void die_gracefully()
  537. {
  538.      syslog(LOG_INFO, "Terminate signal caught...");
  539.      send_flush_notice(HM_FLUSH);
  540.      (void)unlink(PidFile);
  541.      closelog();
  542.      exit(0);
  543. }
  544.  
  545. char *
  546. strsave(sp)
  547. char *sp;
  548. {
  549.     register char *ret;
  550.  
  551.     if((ret = malloc((unsigned) strlen(sp)+1)) == NULL) {
  552.         abort();
  553.     }
  554.     (void) strcpy(ret,sp);
  555.     return(ret);
  556. }
  557.